/***************************************************************************
 *	@file 		fetion_sip.h
 *	@Author 	baoyu0125@gmail.com
 *	@create		2011-7
 *	@version 	1.0.0
 *	@brief		definition of class FetionSip,
 *				FetionSip is about sip connection by boost socket, also contain
 *				information of sip message.
 *	@modify		none
 ***************************************************************************/

#ifndef FETION_SIP_H
#define FETION_SIP_H

using boost::asio::ip::tcp;

typedef enum
{
	SIP_EVENT_PRESENCE = 0,
	SIP_EVENT_SETPRESENCE ,
	SIP_EVENT_CONTACT ,
	SIP_EVENT_CONVERSATION ,
	SIP_EVENT_CATMESSAGE ,
	SIP_EVENT_SENDCATMESSAGE ,
	SIP_EVENT_STARTCHAT ,
	SIP_EVENT_INVITEBUDDY ,
	SIP_EVENT_GETCONTACTINFO ,
	SIP_EVENT_CREATEBUDDYLIST ,
	SIP_EVENT_DELETEBUDDYLIST ,
	SIP_EVENT_SETCONTACTINFO ,
	SIP_EVENT_SETUSERINFO ,
	SIP_EVENT_SETBUDDYLISTINFO ,
	SIP_EVENT_DELETEBUDDY ,
	SIP_EVENT_ADDBUDDY ,
	SIP_EVENT_KEEPALIVE ,
	SIP_EVENT_DIRECTSMS ,
	SIP_EVENT_SENDDIRECTCATSMS ,
	SIP_EVENT_HANDLECONTACTREQUEST ,
	SIP_EVENT_PGGETGROUPLIST ,
	SIP_EVENT_PGGETGROUPINFO , 
	SIP_EVENT_PGGETGROUPMEMBERS ,
	SIP_EVENT_PGSENDCATSMS , 
	SIP_EVENT_PGPRESENCE
} SipEvent;

class FetionSip
{
public:
	friend class FetionListener;
	friend class SipProcSipc;
	friend class Conversation;
	
	typedef enum 
	{
		SIP_REGISTER = 1 ,
		SIP_SERVICE ,
	 	SIP_SUBSCRIPTION , 
		SIP_NOTIFICATION ,
		SIP_INVITATION , 
		SIP_INCOMING , 
		SIP_OPTION , 
		SIP_MESSAGE ,
		SIP_SIPC_4_0 ,
		SIP_ACKNOWLEDGE ,
		SIP_UNKNOWN
	} SipType;

	class SipHeader
	{
	public:
		std::string name;
		std::string value;
	};

	FetionSip(std::string sid);
	int connect(std::string ipaddress, unsigned int port);
	void setType(SipType st)
	{
		type = st;
		callid = CallID;
	}

	void addHeader(std::string name, std::string value)
	{
		SipHeader hder;
		hder.name = name;
		hder.value = value;
		header.push_back(hder);
	}
	void addEventHeader(SipEvent eventType);

	int get_send_string(std::string &sipmsg, const std::string &body = "");
	int get_attribute_value(const std::string &sip, const std::string name, std::string &result);
	
	int get_sip_length(const std::string &sip);
	int get_status_code(const std::string &sip);
	
	void send_sip_message(const std::string &msg);
	int receive_sip_response(std::string &res);
	
private:
	SipType type;							/* sip message type						   */
	std::string from;					/* sender`s fetion no ,in sip it`s "F: "  */
	int callid;
	int sequence;						/* sequence number , in sip it`s "Q: "    */
	std::string sipuri;					/* outer sipuri used when listening       */
	std::vector<SipHeader> header;		/* some other header list				   */
	tcp::socket siptcp;

	static int CallID;
};

class SipProc
{
public:
	SipProc(const std::string &msg) : msg_(msg) {}
	virtual int process_received_sip() { return 0; }
	int get_attribute_value(const std::string name, std::string &result) const;
	int get_status_code();
public:
	std::string msg_;
};

class SipProcNotify : public SipProc
{
public:
	typedef enum {
		NOTIFICATION_TYPE_PRESENCE ,
		NOTIFICATION_TYPE_CONTACT ,
		NOTIFICATION_TYPE_CONVERSATION ,
		NOTIFICATION_TYPE_REGISTRATION ,
		NOTIFICATION_TYPE_SYNCUSERINFO ,
		NOTIFICATION_TYPE_PGGROUP ,
		NOTIFICATION_TYPE_UNKNOWN
	} NotificationType;
	
	typedef enum {
		NOTIFICATION_EVENT_PRESENCECHANGED ,
		NOTIFICATION_EVENT_ADDBUDDYAPPLICATION ,
		NOTIFICATION_EVENT_USERLEFT ,
		NOTIFICATION_EVENT_DEREGISTRATION , 
		NOTIFICATION_EVENT_SYNCUSERINFO ,
		NOTIFICATION_EVENT_PGGETGROUPINFO , 
		NOTIFICATION_EVENT_UNKNOWN
	} NotificationEvent;
	
	SipProcNotify(const std::string &msg) : SipProc(msg) {}
	int process_received_sip();
private:
	void process_deregistration() const;
	int process_syncuserinfo(const std::string &xml) const;
	int parse_notification(int &type, int &event, std::string &xml) const;
	int process_addbuddyapplication(const std::string &xml) const;
	int process_presence(const std::string &xml) const;
};

class SipProcSipc : public SipProc
{
public:
	SipProcSipc(const std::string &msg) : SipProc(msg) {}
	int process_received_sip();
};

class Message;
class SipProcMessage : public SipProc
{
public:
	SipProcMessage(const std::string &msg) : SipProc(msg) {}
	int process_received_sip();
private:
	int parse_message(Message &message);
};

#endif
